import {useMemo, useRef, useState} from "react";
import {computed, watch} from "./reactivity";
import type {TopDesignContext} from "./context.type";
import type {SimpleFunction} from "./event.type";
import {renderError} from "../utils/renderError";

/**
 * hook 强制更新
 * @author  韦胜健
 * @date    2021/3/9 18:14
 */
export function useUpdate() {
    const [, setState] = useState(0);
    return () => setState(prev => prev + 1);
}

/**
 * 监听响应式依赖变化，强制更新render
 * @author  韦胜健
 * @date    2021/3/9 18:15
 */
export function useRender<T>(option: {
    render: () => T,
    ctx: TopDesignContext,
    // 当memo依赖变化时，强制重新计算render computed(slot变化不会触发render重新计算)
    memoDependencies: any[],
    onBeforeRender: () => void,
}) {
    const update = useUpdate();
    const unWatchRef = useRef(null as null | SimpleFunction)
    const renderMemo = useMemo(() => {
        const ref = computed(() => {
            option.onBeforeRender()
            try {
                return option.render()
            } catch (e: any) {
                console.error(e)
                return renderError(e)
            }
        });
        if (!!unWatchRef.current) {unWatchRef.current()}
        unWatchRef.current = watch(ref, () => {
            if (option.ctx.isDestroyed) {return unWatchRef.current!()}
            update()
        });
        return ref;
    }, option.memoDependencies)

    return renderMemo.value;
}

/**
 * 执行一次函数参数，但是每次hook都返回第一次的执行结果
 * @author  韦胜健
 * @date    2021/3/9 18:15
 */
export function useOnce<FN extends () => any>(fn: FN): ReturnType<FN> {
    const first = useRef(true)
    const value = useRef<ReturnType<FN>>({} as any)
    if (first.current) {
        first.current = false
        value.current = fn()
    }
    return value.current
}

/**
 * 创建hook manager，用来管理setup中执行的hook
 * @author  韦胜健
 * @date    2021/4/4 19:19
 */
export function useHookManager() {
    return useOnce(() => {
        const hooks = [] as (() => void)[]
        return {
            hookManager: {
                useHook: (hook: () => any) => {
                    const hookReturn = {current: undefined as any}
                    const getter = (() => {
                        let count = 0
                        return () => {
                            if (count === 0) {
                                // console.warn(0)
                                /*第一次执行获取值*/
                                hookReturn.current = hook()
                            } else if (count === 1) {
                                /*第二次执行什么事也不做（因为实际上第一次执行和第二次是在同一次render中执行的）*/
                                // console.warn(1)
                            } else {
                                /*setup执行之后的render执行*/
                                hookReturn.current = hook()
                                // console.warn('>1')
                            }
                            count++
                            return hookReturn
                        }
                    })();
                    hooks.push(getter)
                    return getter()
                },
                execHook: () => {
                    hooks.forEach(hook => hook())
                },
            }
        }
    })
}
